package com.oglvip.business.remote.support.proxy;

import com.oglvip.business.remote.support.annotation.BodyParam;
import com.oglvip.business.remote.support.request.ContentTypes;
import com.oglvip.business.remote.support.request.RequestEntity;
import com.oglvip.business.remote.support.utils.ClassUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * The type Request builder.
 */
public class RequestBuilder {
    private static Logger _logger = LoggerFactory.getLogger(RequestBuilder.class);
    //private static final ParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
    /**
     * Build http request.
     *
     * @param clazz  the clazz
     * @param method the method
     * @param args   the args
     * @return http request
     */
    public static RequestEntity build(Class<?> clazz, Method method, Object[] args) {
        Path servicePath = clazz.getInterfaces()[0].getAnnotation(Path.class);
        String parentPath = "";
        if (servicePath != null) {
            parentPath = servicePath.value();
        }
        Path interfacePath = method.getAnnotation(Path.class);
        String path = "";
        if (interfacePath != null) {
            path = interfacePath.value();
        }
        String host = ProxyFactory.getHost(clazz.getInterfaces()[0]);
        //
        RequestEntity requestEntity = new RequestEntity(host, parentPath, path);

        GET get = method.getAnnotation(GET.class);
        if (get != null) {
            requestEntity.setHttpMethod(RequestEntity.GET);
        }
        POST post = method.getAnnotation(POST.class);
        if (post != null) {
            requestEntity.setHttpMethod(RequestEntity.POST);
        }
        DELETE delete = method.getAnnotation(DELETE.class);
        if (delete != null) {
            requestEntity.setHttpMethod(RequestEntity.DELETE);
        }
        PUT put = method.getAnnotation(PUT.class);
        if (put != null) {
            requestEntity.setHttpMethod(RequestEntity.PUT);
        }

        Consumes consumes = method.getAnnotation(Consumes.class);
        if(consumes != null && StringUtils.isNotBlank(consumes.value()[0])){
            requestEntity.setContentType(consumes.value()[0]);
        } else {
            requestEntity.setContentType("*/*");
        }

        Produces produces = method.getAnnotation(Produces.class);
        if(produces !=null ){
            String accept = StringUtils.join(produces.value(),";");
            if(StringUtils.isNotBlank(accept)){
                requestEntity.setAccept(accept);
            }else{
                requestEntity.setAccept("*/*");
            }
        }else{
            requestEntity.setAccept("*/*");
        }


        if (requestEntity.getHttpMethod() == RequestEntity.GET) {
            buildFormParam(requestEntity, method, args);
        } else if (requestEntity.getHttpMethod() == RequestEntity.POST) {
            if (requestEntity.getContentType().contains(ContentTypes.APPLICATION_FORM_URLENCODED)) {
                buildFormParam(requestEntity, method, args);
            } else if (requestEntity.getContentType().contains(ContentTypes.APPLICATION_JSON)) {
                buildBodyParam(requestEntity, method, args);
            } else if (requestEntity.getContentType().contains(ContentTypes.MULTIPART_FORM_DATA)) {
                //TODO
            }else{
                buildFormParam(requestEntity, method, args);
            }
        } else if (requestEntity.getHttpMethod() == RequestEntity.PUT) {
            buildBodyParam(requestEntity,method,args);
        }

        return requestEntity;
    }


    protected static void buildFormParam(RequestEntity requestEntity, Method method, Object[] args) {
        //TODO 增加bean类型的注解，装配其属性
        Map<String, Object> urlParams = new HashMap<String, Object>();
        Map<String, Object> formParams = new HashMap<String, Object>();
        Annotation[][] annotations = method.getParameterAnnotations();
        if(args == null){
            args = new Object[0];
        }

        if (annotations.length != args.length) {
            _logger.error("error length of arguments when build params...");
            throw new IllegalArgumentException("error length of arguments when build params...");
        }
        for (int i = 0; i < annotations.length; i++) {
            Annotation[] paramAnno = annotations[i];
            for (Annotation annotation : paramAnno) {
                if (annotation instanceof PathParam) {
                    PathParam paramPath = (PathParam) annotation;
                    Pattern pattern = Pattern.compile("\\{\\s*" + paramPath + "\\s*\\}");
                    Matcher pathMatcher = pattern.matcher(requestEntity.getPath());
                    requestEntity.setPath(pathMatcher.replaceAll(String.valueOf(args[i])));
                } else if (annotation instanceof QueryParam) {
                    urlParams.put(((QueryParam) annotation).value(), args[i]);
                } else if (annotation instanceof FormParam) {
                    formParams.put(((FormParam) annotation).value(), args[i]);
                }else if(annotation instanceof BodyParam){
                    Object obj = args[i];
                    formParams.putAll(ClassUtils.getBeanProperties(obj));
                }
            }
        }

        requestEntity.setUrlParams(urlParams);
        requestEntity.setFormParams(formParams);
    }

    public static void buildBodyParam(RequestEntity requestEntity, Method method, Object[] args) {
        if (method.getTypeParameters().length != args.length) {
            _logger.error("error length of arguments when build params...");
            throw new IllegalArgumentException("error length of arguments when build params...");
        }
        if (method.getTypeParameters().length <= 1) {
            requestEntity.setBody(args[0]);
        } else {
            Map<String, Object> map = new HashMap<String, Object>();

            Annotation[][] annotations = method.getParameterAnnotations();
            for (int i = 0; i < annotations.length; i++) {
                Annotation[] paramAnno = annotations[i];
                for (Annotation annotation : paramAnno){
                    if(annotation instanceof BodyParam){
                        map.put(((BodyParam) annotation).value(),args[i]);
                    }
                }
            }
            requestEntity.setBody(map);
        }
    }



    /**
     * spring组建无法读取接口的参数名
     * @param implClass
     * @param method
     * @return
     */
    /*private String[] getMethodParams(Class<?> implClass,Method method){
        try {
            Method impl = implClass.getMethod(method.getName(),method.getParameterTypes());
            return discoverer.getParameterNames(impl);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            _logger.error("method {} cant get parameter names automatically",method.getName());
            return null;
        }
    }*/
}
